package com.onpositive.data.serializer.writers;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;

import com.onpositive.data.serializer.readers.DefaultReaderFactory;

public class StringWriter extends AbstractWriter<String> {

	public static final int DIRECT_STORE = 1;
	public static final int INDIRECT_STORE = 2;
	
	private ArrayList<String> storage = new ArrayList<String>() ;
	private ArrayList<Integer> indexSequence = new ArrayList<Integer>() ;
	private HashMap<String, Integer> map = new HashMap<String, Integer>() ;
	
	public StringWriter()
	{
		super(String.class);
		storage.add("");
	}

	@Override
	public void append(String str)
	{		
		if(str == null )
			indexSequence.add( 0 ) ;

		else{
		
			Integer ind = map.get( str ) ;
			
			if( ind == null )
			{
				ind = storage.size() ;
				storage.add( str ) ;
				map.put( str, ind ) ;
			}
			
			indexSequence.add( ind ) ;
		}
	}

	@Override
	protected void doSerialize()
	{
		int l1 = INT_SIZE*( indexSequence.size() + 1 ) ;
		int l2 = INT_SIZE*( indexSequence.size() + storage.size() + 1 ) ;
		
		try{
			for( Integer i : indexSequence )
				l1 += ( 2 + storage.get(i).getBytes("UTF-8").length ) ;
	
			for( String s : storage )
				l2 += ( 2 + s.getBytes("UTF-8").length ) ;
		
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		if( l2 > l1 )
		{			
			ArrayList<Integer> offsets = new ArrayList<Integer>( indexSequence.size() + 1 ) ;			
			
			int sizeInBytes = 0 ;
			offsets.add( 0 ) ;
			try{
				for( Integer i : indexSequence )
					offsets.add( sizeInBytes += ( 2+storage.get(i).getBytes("UTF-8").length ) ) ;

			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			
			
			sizeInBytes += super.getDataOffset() + INT_SIZE * ( 4 + offsets.size() ) ;
			super.writeIntToStream( sizeInBytes ) ;
			super.writeIntToStream( DIRECT_STORE ) ;
			super.writeIntToStream( indexSequence.size() ) ;
			super.writeIntToStream( Integer.MAX_VALUE ) ;//just to normalize output
			
			int dataOffset = super.getDataOffset() + INT_SIZE * offsets.size() ;
			
			for( Integer i : offsets )
				super.writeIntToStream( i + dataOffset ) ;
			
			for( Integer i : indexSequence )
				super.writeStringUTFToStream( storage.get(i) ) ;
		}
		else{
			
			ArrayList<Integer> offsets = new ArrayList<Integer>( storage.size() + 1 ) ;			
			int sizeInBytes = 0 ;
			offsets.add( sizeInBytes ) ;

			try {
				for( String s : storage )
					offsets.add( sizeInBytes += ( 2 + s.getBytes("UTF-8").length )  ) ;
				
			} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
			}
		
			sizeInBytes += super.getDataOffset() + INT_SIZE * ( 4 + offsets.size() + indexSequence.size() ) ;
			super.writeIntToStream( sizeInBytes ) ;
			super.writeIntToStream( INDIRECT_STORE ) ;			
			super.writeIntToStream( indexSequence.size() ) ;
			super.writeIntToStream( storage.size() ) ;
			
			int dataOffset = super.getDataOffset() + INT_SIZE * ( offsets.size() + indexSequence.size() ) ;			
			
			for( Integer i : offsets )
				super.writeIntToStream( i + dataOffset ) ;
			
			for( Integer i : indexSequence )
				super.writeIntToStream( i ) ;		
			
			for( String s : storage )
				super.writeStringUTFToStream( s ) ;
		}
	}

	@Override
	protected int getID()
	{
		return DefaultReaderFactory.RW_ID_STRING ;				
	}

}

